<template>
    <el-scrollbar @contextmenu.prevent>
        <div class="file-list-container no-user-select">
            <el-breadcrumb :separator-class="ArrowRight">
                <el-breadcrumb-item v-for="(part, index) in pathParts" :key="index" @click="handleBreadcrumbClick(index)">
                    {{ part || '根目录' }}
                </el-breadcrumb-item>
            </el-breadcrumb>
            <!-- 遍历文件列表，渲染每个文件项 -->
            <div
                v-for="(file, index) in fileList"
                :key="index"
                class="file-item"
                :class="{ 'is-hovered': hoverIndex === index }"
                v-loading="isLoading"
                @mouseenter="handleMouseEnterFileList(index)"
                @mouseleave="handleMouseLeaveFileList"
                @click="handleDirectoryOrFileClick(file)"
                @contextmenu.prevent="showContextMenu($event, file)"
            >
                <div class="file-icon">
                    <!-- 根据文件类型显示不同图标 -->
                    <el-icon v-if="file.isDirectory" :size="24">
                        <Folder32Regular />
                    </el-icon>
                    <el-icon v-if="!file.isDirectory" :size="24">
                        <Document32Regular />
                    </el-icon>
                </div>
                <div class="file-info">
                    <div class="file-name">{{ file.name }}</div>
                    <div class="file-size">{{ byteToMb(file.size) }}</div>
                    <div class="file-mtimeMs-at">修改时间: {{ dayjs(file.mtimeMs).format('YYYY/MM/DD HH:mm:ss') }}</div>
                    <div class="file-birthtimeMs-at">创建时间: {{ dayjs(file.birthtimeMs).format('YYYY/MM/DD HH:mm:ss') }}</div>
                </div>
            </div>
        </div>
    </el-scrollbar>
    <!-- 引入右键菜单组件 -->
    <CustomContextMenu ref="contextMenu" :menuItems="menuItems" />

    <!-- 预览组件 -->
    <ScanImg v-model:show-preview-img="showPreviewImg" :img-src-list="imgSrcList"></ScanImg>
    <!-- PDF 预览弹窗 -->
    <ScanPdf v-model:show-pdf-preview="showPdfPreview" :pdfData="pdfData"></ScanPdf>
    <!-- Excel 预览弹窗 -->
    <ScanExcel v-model:show-excel-preview="showExcelPreview" :excel-data="excelData"></ScanExcel>
    <!-- word 预览弹窗 -->
    <ScanWord v-model:show-word-preview="showWordPreview" :word-data="wordData"></ScanWord>
</template>

<script setup lang="ts">
import { copyFileApi, createFolderApi, deleteFileApi, getFileList, moveFileApi, renameFileApi } from '@/api/file';
import { byteToMb } from 'numb-tools';
import { Folder32Regular, Document32Regular } from '@vicons/fluent';
import { ArrowRight } from '@element-plus/icons-vue';
import dayjs from 'dayjs';
import { previewStaticFile } from '@/api/download';
import CustomContextMenu from '@/components/CustomContextMenu/CustomContextMenu.vue';
import { checkPermi } from '@/utils/permission';
import { useSystemStore } from '@/store/modules/system';

// 组件挂载时获取文件列表
onMounted(async () => {
    await getFileListApi();
});

/* ***********************************加载属性/方法*********************************** */
// 定义加载状态
const isLoading = ref(false);

/* ***********************************当前路径文件夹属性/方法*********************************** */
// 定义文件列表数据
type FileList = {
    name: string;
    size: number;
    isDirectory: boolean;
    atimeMs: number;
    mtimeMs: number;
    ctimeMs: number;
    birthtimeMs: number;
    path?: string;
}[];
const path = ref('根目录');
const fileList = reactive<FileList>([]);
// 获取文件列表
const getFileListApi = async () => {
    isLoading.value = true; // 开始加载
    fileList.length = 0; // 清空文件列表
    const res = await getFileList(path.value.replace(/根目录/g, 'files'));
    if (res.code === 200) {
        res.data.forEach((item) => {
            fileList.push(item);
        });
        isLoading.value = false; // 加载完成
    } else {
        ElMessage.error(res.message);
        isLoading.value = false; // 加载失败
    }
};

/* ***********************************预览文件属性/方法*********************************** */
// 目录或文件点击事件处理函数
const handleDirectoryOrFileClick = (file: FileList[number]) => {
    // 如果是目录，更新路径并重新获取文件列表
    if (file.isDirectory) {
        path.value = path.value + '/' + file.name;
        getFileListApi();
    } else {
        // 处理文件点击事件，检查文件类型并准备预览数据
        // 权限校验
        if (!checkPermi(['file-show'])) {
            ElMessage.warning('您没有权限查看此文件');
            return;
        }
        const fileExtension = getFileExtension(file.name);
        // 图片类型预览
        if (['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].includes(fileExtension)) {
            // 如果是图片文件，直接预览
            showPreviewImg.value = true; // 显示图片预览
            // 加工图片路径
            imgSrcList.value.length = 0;
            imgSrcList.value.push(import.meta.env.VITE_APP_SERVER_URL + path.value.split(/根目录/g)[1] + '/' + file.name);
            return;
        }

        // pdf类型预览
        if (['pdf'].includes(fileExtension)) {
            // 如果是pdf文件，直接预览
            handlePdfFileData(path.value.split(/根目录/g)[1] + '/' + file.name); // 显示pdf预览
            return;
        }

        // excel类型预览
        if (['xlsx', 'xls'].includes(fileExtension)) {
            // 如果是excel文件，直接预览
            handleExcelFileData(path.value.split(/根目录/g)[1] + '/' + file.name);
            return;
        }

        // docx类型预览
        if (['docx'].includes(fileExtension)) {
            // 如果是docx文件，直接预览
            handleDocxFileData(path.value.split(/根目录/g)[1] + '/' + file.name);
            return;
        }

        // 如果是其他文件类型，提示不支持预览
        ElMessage.warning('不支持预览此文件类型');
    }
};
// 获取文件后缀
const getFileExtension = (fileName: string) => {
    const index = fileName.lastIndexOf('.');
    if (index !== -1) {
        return fileName.substring(index + 1).toLowerCase();
    } else {
        return '';
    }
};
// 图片预览
const showPreviewImg = ref(false);
const imgSrcList = ref<string[]>([]);
// pdf预览
const showPdfPreview = ref(false);
const pdfData = ref();
// 加载DPF文件
const handlePdfFileData = async (src: string) => {
    try {
        isLoading.value = true; // 开始加载
        // 使用 fetch 获取文件内容
        const response = await previewStaticFile(src);
        // 检查 Blob 是否有效
        if (!response || response.size === 0) {
            ElMessage({
                message: '读取文件失败，请稍后重试',
                type: 'error',
                grouping: true,
            });
            throw new Error('Failed to fetch valid file');
        }

        // 创建 FileReader 实例
        const reader = new FileReader();

        // 当读取完成时
        reader.onload = () => {
            // 需要传递给子组件的数据
            pdfData.value = reader.result;
            // 打开弹窗
            showPdfPreview.value = true;
            // 加载完成
            isLoading.value = false;
        };

        // 读取 Blob 内容
        reader.readAsArrayBuffer(response as unknown as Blob);
    } catch (error) {
        console.error('Error reading file:', error);
        ElMessage({
            message: '读取文件失败，请稍后重试',
            type: 'error',
            grouping: true,
        });
    }
};
// Excel 预览
const showExcelPreview = ref(false);
const excelData = ref<ArrayBuffer>();
// 加载 Excel 文件
const handleExcelFileData = async (src: string) => {
    try {
        // 开始加载
        isLoading.value = true;
        // 下载文件内容
        const response = await previewStaticFile(src);
        // 检查 Blob 是否有效
        if (!response || response.size === 0) {
            ElMessage({
                message: '读取文件失败，请稍后重试',
                type: 'error',
                grouping: true,
            });
            throw new Error('Failed to fetch valid file');
        }

        const reader = new FileReader();
        reader.onload = () => {
            showExcelPreview.value = true;
            if (!(reader.result instanceof ArrayBuffer)) {
                ElMessage({
                    message: '读取 Excel 文件失败，请稍后重试',
                    type: 'error',
                    grouping: true,
                });
                return;
            }
            excelData.value = reader.result;
            // 加载完成
            isLoading.value = false;
        };

        // 读取 Blob 内容
        reader.readAsArrayBuffer(response as unknown as Blob);
    } catch (error) {
        console.error('Error reading Excel file:', error);
        ElMessage({
            message: '读取 Excel 文件失败，请稍后重试',
            type: 'error',
            grouping: true,
        });
        isLoading.value = false;
    }
};
// docx 预览
const showWordPreview = ref(false);
const wordData = ref<ArrayBuffer>();
// 加载 docx 文件
const handleDocxFileData = async (src: string) => {
    try {
        // 开始加载
        isLoading.value = true;
        // 下载文件内容
        const response = await previewStaticFile(src);
        // 检查 Blob 是否有效
        if (!response || response.size === 0) {
            ElMessage({
                message: '读取文件失败，请稍后重试',
                type: 'error',
                grouping: true,
            });
            throw new Error('Failed to fetch valid file');
        }

        const reader = new FileReader();
        reader.onload = () => {
            showWordPreview.value = true;
            if (!(reader.result instanceof ArrayBuffer)) {
                ElMessage({
                    message: '读取 docx 文件失败，请稍后重试',
                    type: 'error',
                    grouping: true,
                });
                return;
            }
            wordData.value = reader.result;
            // 加载完成
            isLoading.value = false;
        };

        // 读取 Blob 内容
        reader.readAsArrayBuffer(response as unknown as Blob);
    } catch (error) {
        console.error('Error reading docx file:', error);
    }
};

/* ***********************************右键菜单属性/方法*********************************** */
// 定义右键菜单实例和当前文件
const contextMenu = ref<InstanceType<typeof CustomContextMenu>>();
// 定义当前文件
const currentFile = ref<FileList[0] | null>(null);
// 复制文件
const copyFile = ref<FileList[0] | null>(null);
// 移动文件
const moveFile = ref<FileList[0] | null>(null);

// 定义右键菜单选项
const menuItems = ref<{ label: string; action: () => void }[]>([
    {
        label: '新建文件夹',
        action: async () => {
            // 权限校验
            if (!checkPermi(['file-edit'])) {
                ElMessage.warning('您没有权限新建文件夹');
                return;
            }

            // 必须是文件夹
            if (!currentFile.value?.isDirectory) {
                ElMessage({
                    message: '仅文件夹可新建文件夹',
                    type: 'warning',
                    grouping: true,
                });
            }

            // 使用 El 组件来实现新建文件夹功能
            ElMessageBox.prompt('请输入新的文件夹名称', '提示', {
                confirmButtonText: '确认',
                cancelButtonText: '取消',
                inputPattern: /^[\u4e00-\u9fa5a-zA-Z0-9_\-.]+$/,
                inputErrorMessage: '仅允许输入字母、数字、中文、下划线、连字符和点号',
                inputValue: '新建文件夹',
            }).then(({ value }) => {
                // 调用后端接口进行新建文件夹操作
                createFolderApi(path.value.split('根目录')[1] + '/' + currentFile.value?.name, value).then((res) => {
                    if (res.code === 200) {
                        ElMessage({
                            message: res.message,
                            type: 'success',
                            grouping: true,
                        });
                        path.value = path.value + '/' + currentFile.value?.name + '/' + value;
                        // 刷新文件列表
                        getFileListApi();
                    }
                });
            });
        },
    },
    {
        label: '下载',
        action: async () => {
            // 权限校验
            if (!checkPermi(['file-show'])) {
                ElMessage.warning('您没有权限下载此文件');
                return;
            }
            // 仅下载文件
            if (currentFile.value?.isDirectory) {
                ElMessage({
                    message: '仅下载文件',
                    type: 'warning',
                    grouping: true,
                });
                return;
            }
            // 浏览器默认提示
            ElMessage({
                dangerouslyUseHTMLString: true,
                message:
                    '<p>如果在浏览器选项中设置了<code>每次下载都询问我该做些什么</code>可能会导致文件不会下载。</p><a href="edge://settings/downloads#All" target="_blank">前往设置</a>',
                type: 'info',
                grouping: true,
            });
            // 使用a标签download下载文件
            const a = document.createElement('a');
            a.href = import.meta.env.VITE_APP_SERVER_URL + path.value.split('根目录')[1] + '/' + currentFile.value?.name;
            a.download = currentFile.value?.name || ''; // 设置下载的文件名
            a.style.display = 'none'; // 隐藏a标签
            a.click(); // 模拟点击事件触发下载
            a.remove(); // 移除a标签
        },
    },
    {
        label: '复制',
        action: () => {
            // 权限校验
            if (!checkPermi(['file-edit'])) {
                ElMessage.warning('您没有权限复制此文件');
                return;
            }

            // 根目录禁止操作
            if (path.value === '根目录') {
                ElMessage({
                    message: '根目录禁止操作',
                    type: 'error',
                    grouping: true,
                });
                return;
            }

            // 如果没有记录当前文件，提示用户选择文件
            if (currentFile.value) {
                // 如果是文件夹，暂不提供服务
                if (currentFile.value.isDirectory) {
                    ElMessage({
                        message: '复制文件夹功能暂未开放',
                        type: 'warning',
                        grouping: true,
                    });
                    return;
                } else {
                    copyFile.value = currentFile.value;
                    copyFile.value.path = path.value;
                    ElMessage({
                        message: '复制成功',
                        type: 'success',
                        grouping: true,
                    });
                }
            } else {
                ElMessage({
                    message: '没有当前文件夹信息',
                    type: 'error',
                    grouping: true,
                });
            }
        },
    },
    {
        label: '粘贴',
        action: async () => {
            // 权限校验
            if (!checkPermi(['file-edit'])) {
                ElMessage.warning('您没有权限粘贴此文件');
                return;
            }

            // 如果没有记录复制文件
            if (!copyFile.value) {
                ElMessage({
                    message: '没有可用复制的文件',
                    type: 'error',
                    grouping: true,
                });
                return;
            }

            // 如果没有记录当前文件，提示用户选择文件
            if (!currentFile.value) {
                ElMessage({
                    message: '没有当前文件夹信息',
                    type: 'error',
                    grouping: true,
                });
            } else {
                // 如果是文件，则提示错误
                if (currentFile.value.isDirectory) {
                    const _copyFile = copyFile.value.path?.split('根目录')[1] + '/' + copyFile.value.name;
                    const _pasteFile = path.value.split('根目录')[1] + '/' + currentFile.value.name + '/';
                    // 请求后端接口进行文件粘贴操作
                    const copyResult = await copyFileApi(_copyFile, _pasteFile);
                    if (copyResult.code === 200) {
                        ElMessage({
                            message: copyResult.message,
                            type: 'success',
                            grouping: true,
                        });
                        // 进入粘贴的文件夹
                        path.value = path.value + '/' + currentFile.value.name;
                        getFileListApi();
                    }
                } else {
                    ElMessage({
                        message: '仅粘贴到文件夹内',
                        type: 'warning',
                        grouping: true,
                    });
                }
            }
        },
    },
    {
        label: '移动',
        action: async () => {
            // 权限校验
            if (!checkPermi(['file-edit'])) {
                ElMessage.warning('您没有权限移动此文件');
                return;
            }

            // 根目录禁止操作
            if (path.value === '根目录') {
                ElMessage({
                    message: '根目录禁止操作',
                    type: 'error',
                    grouping: true,
                });
                return;
            }

            // 右键菜单修改
            for (let index = 0; index < menuItems.value.length; index++) {
                const mi = menuItems.value[index];
                if (mi.label == '移动') {
                    // 如果没有记录当前文件，提示用户选择文件
                    if (!currentFile.value) {
                        ElMessage({
                            message: '没有当前文件夹信息',
                            type: 'error',
                            grouping: true,
                        });
                    } else if (currentFile.value.isDirectory) {
                        ElMessage({
                            message: '移动文件夹功能暂未开放',
                            type: 'warning',
                            grouping: true,
                        });
                    } else {
                        // 记录当前文件
                        moveFile.value = currentFile.value;
                        moveFile.value.path = path.value;
                        ElMessage({
                            message: '请移至目标文件夹，开始移动',
                            type: 'success',
                            grouping: true,
                        });
                        // 修改右键菜单
                        mi.label = '移动到此文件夹';
                        return;
                    }
                } else if (mi.label == '移动到此文件夹') {
                    // 开始移动
                    if (moveFile.value) {
                        const _moveFile = moveFile.value.path?.split('根目录')[1] + '/' + moveFile.value.name;
                        const _pasteFile = path.value.split('根目录')[1] + '/' + currentFile.value!.name + '/';
                        // 请求后端接口进行文件移动操作
                        const moveResult = await moveFileApi(_moveFile, _pasteFile);
                        if (moveResult.code === 200) {
                            ElMessage({
                                message: moveResult.message,
                                type: 'success',
                                grouping: true,
                            });
                            // 修改右键菜单
                            mi.label = '移动';
                        }
                        return;
                    }
                }
            }
        },
    },
    {
        label: '重命名',
        action: () => {
            // 权限校验
            if (!checkPermi(['file-edit'])) {
                ElMessage.warning('您没有权限重命名此文件');
                return;
            }

            // 根目录禁止操作
            if (path.value === '根目录') {
                ElMessage({
                    message: '根目录禁止操作',
                    type: 'error',
                    grouping: true,
                });
                return;
            }

            // 如果没有记录当前文件，提示用户选择文件
            if (currentFile.value) {
                // 使用 El 组件来实现重命名功能
                ElMessageBox.prompt('请输入新的文件夹名称', '提示', {
                    confirmButtonText: '确认',
                    cancelButtonText: '取消',
                    inputValue: currentFile!.value!.name,
                    // 仅允许输入字母、数字、中文、下划线、连字符和点号
                    inputPattern: /^[\u4e00-\u9fa5a-zA-Z0-9_\-.]+$/,
                    inputErrorMessage: '仅允许输入字母、数字、中文、下划线、连字符和点号',
                }).then(({ value }) => {
                    // 调用后端接口进行重命名操作
                    renameFileApi(path.value.split('根目录')[1] + '/' + currentFile!.value!.name, path.value.split('根目录')[1] + '/' + value).then(
                        (res) => {
                            if (res.code === 200) {
                                ElMessage({
                                    message: res.message,
                                    type: 'success',
                                    grouping: true,
                                });
                                getFileListApi(); // 刷新文件列表
                            }
                        }
                    );
                });
            } else {
                ElMessage({
                    message: '没有当前文件夹信息',
                    type: 'error',
                    grouping: true,
                });
            }
        },
    },
    {
        label: '删除',
        action: async () => {
            // 权限校验
            if (!checkPermi(['file-delete'])) {
                ElMessage.warning('您没有权限删除此文件');
                return;
            }

            // 根目录禁止操作
            if (path.value === '根目录') {
                ElMessage({
                    message: '根目录禁止操作',
                    type: 'error',
                    grouping: true,
                });
                return;
            }
            // 如果没有记录当前文件，提示用户选择文件
            if (!currentFile.value) {
                ElMessage({
                    message: '没有当前文件夹信息',
                    type: 'error',
                    grouping: true,
                });
                return;
            } else if (currentFile.value.isDirectory) {
                ElMessage({
                    message: '删除文件夹功能暂未开放',
                    type: 'warning',
                    grouping: true,
                });
            } else {
                const deleteResult = await deleteFileApi(path.value.split('根目录')[1] + '/' + currentFile.value?.name);
                if (deleteResult.code === 200) {
                    ElMessage({
                        message: deleteResult.message,
                        type: 'success',
                        grouping: true,
                    });
                    getFileListApi();
                }
            }
        },
    },
]);

// 显示右键菜单
const showContextMenu = (event: MouseEvent, file: FileList[0]) => {
    // 记录当前文件
    currentFile.value = file;
    // 显示右键菜单
    contextMenu.value?.showMenu(event);
};

/* ***********************************面包屑属性/方法*********************************** */
// 定义面包屑路径数组
const pathParts = ref(path.value.split('/'));
// 监听路径变化，更新面包屑路径数组
watch(path, () => {
    pathParts.value = path.value.split('/');
});
// 面包屑点击事件处理函数
const handleBreadcrumbClick = (index: number) => {
    path.value = pathParts.value.slice(0, index + 1).join('/');
    getFileListApi();
};

/* ***********************************css交互属性/方法*********************************** */
// 记录当前悬停的文件项索引
const hoverIndex = ref(-1);
// 鼠标进入文件项
const handleMouseEnterFileList = (index: number) => {
    hoverIndex.value = index;
};
// 鼠标离开文件项
const handleMouseLeaveFileList = () => {
    hoverIndex.value = -1;
};

// 系统配置
const useSystem = useSystemStore();
// 计算宽度
const fileListWidth = computed(() => {
    return useSystem.config.isCollapse ? 'calc(100vw - 84px)' : 'calc(100vw - 220px)';
});
</script>

<style scoped>
.file-list-container {
    height: calc(100vh - 80px);
    width: v-bind(fileListWidth);
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    padding: 1.5rem;
    /* 更明亮的灰色调渐变背景 */
    background: linear-gradient(135deg, #f0f0f0, #e0e0e0);
    /* 调整淡蓝色发光效果 */
    box-shadow: 0 0 40px rgba(30, 144, 255, 0.3), 0 0 80px rgba(30, 144, 255, 0.15);
    cursor: default;
    /* 添加呼吸动画 */
    animation: pulse 5s infinite alternate;
}

/* 新增 current-path 样式 */
.current-path {
    color: #a7d9f7;
    font-size: 1.2rem;
    font-weight: 600;
    padding: 0.8rem 1.2rem;
    background-color: rgba(255, 255, 255, 0.1);
    border-radius: 8px;
    border: 2px solid rgba(30, 144, 255, 0.3);
    text-shadow: 0 0 5px rgba(30, 144, 255, 0.3);
    box-shadow: 0 2px 8px rgba(30, 144, 255, 0.1);
    transition: all 0.3s ease;
    margin-bottom: 1rem;
}

.current-path:hover {
    border-color: #1e90ff;
    box-shadow: 0 0 20px rgba(30, 144, 255, 0.3);
    transform: translateY(-2px);
}

/* 呼吸动画 */
@keyframes pulse {
    0% {
        box-shadow: 0 0 40px rgba(30, 144, 255, 0.3), 0 0 80px rgba(30, 144, 255, 0.15);
    }
    100% {
        box-shadow: 0 0 60px rgba(30, 144, 255, 0.5), 0 0 120px rgba(30, 144, 255, 0.25);
    }
}

.file-item {
    display: flex;
    align-items: center;
    gap: 1.2rem;
    padding: 1.2rem;
    /* 更明亮的半透明背景 */
    background-color: rgba(255, 255, 255, 0.8);
    border-radius: 12px;
    /* 调整淡蓝色边框 */
    border: 2px solid rgba(30, 144, 255, 0.3);
    transition: all 0.3s ease;
    transform: translateY(0);
    /* 毛玻璃效果 */
    backdrop-filter: blur(10px);
    cursor: pointer;
}

.file-item.is-hovered {
    /* 动态边框颜色 */
    border-color: #1e90ff;
    box-shadow: 0 0 30px rgba(30, 144, 255, 0.5), 0 0 60px rgba(30, 144, 255, 0.25);
    transform: translateY(-5px);
}

.file-icon {
    font-size: 2rem;
    /* 图标颜色 */
    color: #1e90ff;
    transition: transform 0.3s ease;
    /* 添加旋转动画 */
    will-change: transform;
}

.file-item.is-hovered .file-icon {
    transform: scale(1.2) rotate(10deg);
}

.file-info {
    display: flex;
    flex-direction: row;
    flex-grow: 1;
    gap: 1.5rem;
    align-items: center;
}

.file-name {
    /* 提升文字颜色亮度 */
    color: #333333;
    font-weight: 400;
    font-size: 1rem;
    transition: color 0.3s ease;
    /* 文字阴影 */
    text-shadow: 0 0 5px rgba(30, 144, 255, 0.3);
    flex: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.file-item.is-hovered .file-name {
    color: #1e90ff;
    /* 悬停时增强文字阴影 */
    text-shadow: 0 0 10px rgba(30, 144, 255, 0.6);
}

.file-size {
    /* 提升文字颜色亮度 */
    color: #666666;
    font-size: 1rem;
    /* 文字阴影 */
    text-shadow: 0 0 3px rgba(30, 144, 255, 0.2);
}

.file-mtimeMs-at,
.file-birthtimeMs-at {
    /* 提升文字颜色亮度 */
    color: #666666;
    font-size: 0.9rem;
    text-shadow: 0 0 3px rgba(30, 144, 255, 0.2);
}
</style>
